﻿using VoucherGridCtl.Commons;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using static VoucherGridCtl.Commons.Consts;

namespace VoucherGridCtl
{
    /// <summary>
    /// VoucherGrid.xaml 的交互逻辑
    /// </summary>
    public partial class VoucherGrid : UserControl
    {
        static int MAX_ROWS = 100;
        static int MAX_COLUMNS = 5;

        string[,] m_Controls = new string[MAX_ROWS, MAX_COLUMNS];

        string m_LastFocusControl = "";

        //定义事件参数类
        public class RowChangeEventArgs : EventArgs
        {
            public int OldRowIndex { set; get; }
            public int RowIndex { set; get; }
            /// <summary>
            /// true  焦点返回上一
            /// </summary>
            public bool Cancel { set; get; }
        }
        //定义delegate
        public delegate void RowChangeEventHandler(object sender, RowChangeEventArgs e);
        //用event 关键字声明事件对象
        public event RowChangeEventHandler RowChangeEvent;    

        protected void OnRowChangeEvent(Control sender,int OldRowIndex,int RowIndex) {
            if (RowChangeEvent == null)
                return;
            RowChangeEventArgs args = new RowChangeEventArgs();
            args.OldRowIndex = OldRowIndex;
            args.RowIndex = RowIndex;
            RowChangeEvent(grid, args);
            if (args.Cancel)
            {
                SetLastFocus();
                throw new FinanceAccountControlException(FinanceAccountControlErrorCode.CANCEL);
            }
        }

        public VoucherGrid()
        {            
            InitializeComponent();           
        }

        List<VoucherGridItem> m_DataSource = new List<VoucherGridItem>();
        public List<VoucherGridItem> DataSource { get { HoldDataSource(); return m_DataSource; } set { m_DataSource = value; } }

        public int CurrentRowIndex { set; get; } = -1;

        bool isReadOnly = false;
        public bool IsReadOnly
        {
            get { return isReadOnly; }
            set {
                isReadOnly = value;
                for (int i = 0; i < MAX_ROWS; i++)
                {
                    for (int j = 0; j < MAX_COLUMNS; j++)
                    {
                        if (j > 0 && j < 5)
                        {
                            var ctlName = m_Controls[i, j];
                            if (ctlName == null || string.IsNullOrEmpty(ctlName))
                                return;
                            var ctl = grid.FindName(ctlName);
                            if (ctl == null)
                                return;
                            if (j == 1)
                            {
                                (ctl as TextBox).IsReadOnly = isReadOnly;
                            }
                            else if (j == 2)
                            {
                                (ctl as AccountSubjectBox).IsReadOnly = isReadOnly;
                            }
                            else if (j == 3 || j == 4)
                            {
                                (ctl as AmountInputBox).IsEnabled = !isReadOnly;
                            }
                        }
                    }
                }
            }
        }

        public void Clear()
        {
            m_DataSource.Clear();
            CurrentRowIndex = -1;
            Refresh();
        }

        public void AppendRow()
        {
            HoldDataSource();
            m_DataSource.Add(new VoucherGridItem());
            Refresh();
        }

        public void InsertRow(int index)
        {
            if (index >= 0)
            {
                HoldDataSource();
                m_DataSource.Insert(index, new VoucherGridItem());                
                Refresh();
            }
        }

        public void DeleteRow(int index)
        {
            if (index >=0)
            {
                HoldDataSource();
                m_DataSource.RemoveAt(index);
                CurrentRowIndex = index-1;
                Refresh();
            }
        }

        /// <summary>
        /// 生效，把数据刷到界面上
        /// </summary>
        public void Refresh()
        {
            ReleaseControls();
            if(grid.RowDefinitions.Count>0)
                grid.RowDefinitions.RemoveRange(0, grid.RowDefinitions.Count);
            int index = 0;
            m_DataSource.ForEach(item =>
            {
                var row = new RowDefinition();
                row.Height = new GridLength(60);
                grid.RowDefinitions.Add(row);

                Label lblIndex = new Label();
                lblIndex.Name = "lblIndex" + index;
                lblIndex.Background = Consts.HIGHLIGHT_BRUSH;
                lblIndex.VerticalContentAlignment = VerticalAlignment.Center;
                lblIndex.BorderBrush = Consts.BLACK_BRUSH;
                lblIndex.BorderThickness = new Thickness(1, 0, 1, 1);
                lblIndex.Content = index + 1;
                lblIndex.GotFocus += Row_GotFocus;

                grid.RegisterName("lblIndex" + index, lblIndex);
                grid.Children.Add(lblIndex);
                m_Controls[index, 0] = "lblIndex" + index;
                lblIndex.SetValue(Grid.RowProperty, index);
                lblIndex.SetValue(Grid.ColumnProperty, 0);

                TextBox txtContent = new TextBox();
                txtContent.Name = "txtContent" + index;
                txtContent.BorderBrush = Consts.BLACK_BRUSH;
                txtContent.BorderThickness = new Thickness(0, 0, 1, 1);
                txtContent.TextWrapping = TextWrapping.Wrap;
                txtContent.Text = item.Content;

                txtContent.KeyDown += (sender, e) =>
                {
                    if (!IsEnabled)
                    {
                        e.Handled = true;
                        return;
                    }
                    if (e.Key == Key.Enter)
                    {
                        Commons.Keyboard.Press(Key.Tab);
                    }
                };
                txtContent.GotFocus += Row_GotFocus;
                txtContent.GotFocus += (sender, e) =>
                {
                    if (isReadOnly)
                        return;
                    var ctl = sender as Control;
                    ctl.Background = Consts.HIGHLIGHT_BRUSH;
                };
                txtContent.LostFocus += (sender, e) =>
                {
                    if (isReadOnly)
                        return;
                    var ctl = sender as Control;
                    ctl.Background = Consts.WHITE_BRUSH;
                };

                grid.RegisterName("txtContent" + index, txtContent);
                grid.Children.Add(txtContent);
                m_Controls[index, 1] = "txtContent" + index;
                Grid.SetRow(txtContent, index);
                Grid.SetColumn(txtContent, 1);

                AccountSubjectBox txtAccountSubject = new AccountSubjectBox();
                txtAccountSubject.Name = "txtAccountSubject" + index;
                txtAccountSubject.BorderBrush = Consts.BLACK_BRUSH;
                txtAccountSubject.BorderThickness = new Thickness(0, 0, 1, 1);                
                txtAccountSubject.Id=item.AccountSubjectId;
                txtAccountSubject.IsReadOnly = this.IsReadOnly;
                txtAccountSubject.GotFocus += Row_GotFocus;

                grid.RegisterName("txtAccountSubject" + index, txtAccountSubject);
                grid.Children.Add(txtAccountSubject);
                m_Controls[index, 2] = "txtAccountSubject" + index;
                Grid.SetRow(txtAccountSubject, index);
                Grid.SetColumn(txtAccountSubject, 2);

                AmountInputBox aInputDebits = new AmountInputBox();
                aInputDebits.Name = "aInputDebits" + index;
                aInputDebits.BorderBrush = Consts.BLACK_BRUSH;
                aInputDebits.BorderThickness = new Thickness(0, 0, 1, 1);
                aInputDebits.Value = item.DebitsAmount;
                aInputDebits.IsEnabled = !this.IsReadOnly;
                aInputDebits.GotFocus += Row_GotFocus;
                aInputDebits.LostFocus += AInputDebits_LostFocus;
                aInputDebits.KeyDown += AInputDebits_KeyDown;

                grid.RegisterName("aInputDebits" + index, aInputDebits);
                grid.Children.Add(aInputDebits);
                m_Controls[index, 3] = "aInputDebits" + index;
                Grid.SetRow(aInputDebits, index);
                Grid.SetColumn(aInputDebits, 3);

                AmountInputBox aInputCredit = new AmountInputBox();
                aInputCredit.Name = "aInputCredit" + index;
                aInputCredit.BorderBrush = Consts.BLACK_BRUSH;
                aInputCredit.BorderThickness = new Thickness(0, 0, 1, 1);
                aInputCredit.Value = item.CreditAmount;
                aInputCredit.IsEnabled = !this.IsReadOnly;
                aInputCredit.GotFocus += Row_GotFocus;
                aInputCredit.LostFocus += AInputCredit_LostFocus;
                aInputCredit.KeyDown += AInputDebits_KeyDown;

                grid.RegisterName("aInputCredit" + index, aInputCredit);
                grid.Children.Add(aInputCredit);
                m_Controls[index, 4] = "aInputCredit" + index;
                Grid.SetRow(aInputCredit, index);
                Grid.SetColumn(aInputCredit, 4);

                index++;
            });
            CalcTotal();
            SetLastFocus();
        }

        private void SetLastFocus()
        {
            if (!string.IsNullOrEmpty(m_LastFocusControl))
            {
                var ctl = grid.FindName(m_LastFocusControl);
                if (ctl != null)
                {
                    var ele1 = ctl as FrameworkElement;
                    if (ele1 != null)
                    {
                        SetFocus(ele1);
                    }
                }
            }
        }

        private void AInputDebits_KeyDown(object sender, KeyEventArgs e)
        {            
            if (e.Key == Key.OemPlus)
            {
                var dTotalCredit = totalCredit.Value;
                var dTotalDebits = totalDebits.Value;
                (sender as AmountInputBox).Value = 0;
                var name = (sender as FrameworkElement).Name;
                if (name.StartsWith("aInputDebits"))
                {
                    dTotalDebits -= (sender as AmountInputBox).Value;
                }
                else
                {
                    dTotalCredit -= (sender as AmountInputBox).Value;
                }
                var index = int.Parse(name.Substring(12));
                var diff = dTotalDebits - dTotalCredit;
                if (diff > 0)
                {
                    (grid.FindName("aInputCredit" + index) as AmountInputBox).Value = diff;
                }
                else
                {
                    (grid.FindName("aInputDebits" + index) as AmountInputBox).Value = Math.Abs(diff);
                }
                CalcTotal();
            }
        }

        private void AInputCredit_LostFocus(object sender, RoutedEventArgs e)
        {
            CalcTotal();
        }

        private void AInputDebits_LostFocus(object sender, RoutedEventArgs e)
        {
            CalcTotal();
        }

        void CalcTotal()
        {
            int i = 0;
            decimal dTotalCredit = 0M;
            while (i < MAX_ROWS)
            {
                var name = "aInputCredit" + i;
                var ctl = grid.FindName(name);
                if (ctl == null)
                    break;
                var input = ctl as AmountInputBox;
                dTotalCredit += input.Value;
                i++;
            }
            totalCredit.Value = dTotalCredit;

            i = 0;
            decimal dTotalDebits = 0M;
            while (i < MAX_ROWS)
            {
                var name = "aInputDebits" + i;
                var ctl = grid.FindName(name);
                if (ctl == null)
                    break;
                var input = ctl as AmountInputBox;
                dTotalDebits += input.Value;
                i++;
            }
            totalDebits.Value = dTotalDebits;
        }

        void SetFocus(FrameworkElement element)
        {
            Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background,
            new Action(() =>
            {
                var suc = element.Focus();
                System.Windows.Input.Keyboard.Focus(element);
            }));
        }


        private void Row_GotFocus(object sender, RoutedEventArgs e)
        {
            if (isReadOnly)
                return;

            var ctl = sender as Control;
            var name = ctl.Name;            
            if (!string.IsNullOrEmpty(name))
            {
                var sn = name.Substring(name.Length - 1);
                int OldRowIndex = CurrentRowIndex;
                CurrentRowIndex = int.Parse(sn);

                if (OldRowIndex != CurrentRowIndex)
                {
                    try
                    {
                        if (OldRowIndex == -1)
                            return;
                        if (OldRowIndex == grid.RowDefinitions.Count - 1)                       
                            return;

                        var row = DataSource[OldRowIndex];
                        if (row.AccountSubjectId == 0L)
                        {
                            MessageBox.Show("科目不能为空", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                            var ele1 = grid.FindName("txtAccountSubject" + OldRowIndex) as FrameworkElement;
                            SetFocus(ele1);
                            e.Handled = true;
                            return;
                        }
                        else if (row.CreditAmount == 0M && row.DebitsAmount == 0M)
                        {
                            MessageBox.Show("金额不能为零", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);              
                            var ele1 = grid.FindName("aInputDebits" + OldRowIndex) as FrameworkElement;
                            SetFocus(ele1);
                            e.Handled = true;
                            return;
                        }
                       
                        OnRowChangeEvent(ctl,OldRowIndex, CurrentRowIndex);
                    }
                    catch (FinanceAccountControlException ex)
                    {
                        if (ex.HResult == (int)FinanceAccountControlErrorCode.CANCEL)
                            return;
                        else
                            throw ex;
                    }
                }
                m_LastFocusControl = name;          
                if (CurrentRowIndex + 1 == grid.RowDefinitions.Count)
                {
                    e.Handled = true;
                    AppendRow();
                }
            }
        }
        /// <summary>
        /// 释放所有的编辑控件
        /// </summary>
        void ReleaseControls()
        {
            for (int i = 0; i < MAX_ROWS; i++)
            {
                for (int j = 0; j < MAX_COLUMNS; j++)
                {
                    string ctl = m_Controls[i, j];
                    if (ctl != null && !string.IsNullOrEmpty(ctl))
                    {
                        Control c = (Control)(grid.FindName(ctl));
                        grid.Children.Remove(c);
                        grid.UnregisterName(ctl);
                        m_Controls[i, j] = null;
                    }
                    else
                    {
                        return;
                    }
                }
            }
            
        }
        /// <summary>
        /// 暂存数据
        /// </summary>
        void HoldDataSource()
        {
            m_DataSource.Clear();
            for (int i = 0; i < MAX_ROWS; i++)
            {
                VoucherGridItem item = new VoucherGridItem();
                for (int j = 0; j < MAX_COLUMNS; j++)
                {
                    string ctl = m_Controls[i, j];
                    if (ctl != null && !string.IsNullOrEmpty(ctl))
                    {
                        if (j == 1)
                        {
                            item.Content = ((TextBox)(grid.FindName(ctl))).Text;
                        }                       
                        else if (j == 2)
                        {
                            item.AccountSubjectId =((AccountSubjectBox)(grid.FindName(ctl))).Id ;
                        }
                        else if (j == 3)
                        {
                            item.DebitsAmount = ((AmountInputBox)(grid.FindName(ctl))).Value;
                        }
                        else if (j == 4)
                        {
                            item.CreditAmount = ((AmountInputBox)(grid.FindName(ctl))).Value;
                        }
                        
                    }
                    else
                    {
                        goto exitfor;
                    }
                }
                m_DataSource.Add(item);
            exitfor:
                ;
            }


        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            Load();
        }

        public void Load()
        {
            DataSource = new List<VoucherGridItem>();
            DataSource.Add(new VoucherGridItem());
            Refresh();
        }

    }
}
